package com.vogue.supplymall.account.domain.bean;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import com.vogue.ssm.database.util.DealStatus;
import com.vogue.supplymall.account.domain.dao.CodeDao;
import com.vogue.supplymall.account.domain.model.BaseCode;
import com.vogue.supplymall.account.domain.service.impl.SpringContextUtils;
import com.vogue.supplymall.account.exception.CodeIsFullException;
import com.vogue.supplymall.common.constant.ErrorCode;
import com.vogue.supplymall.common.domain.tool.MathUtils;
import com.vogue.supplymall.common.domain.tool.VerifyEnvironmentBean;

/**
 * 放一些常用数据在内存中
 * 例如系统号码和本身id的对应关系
 * @author 崔岳
 *
 */
@Component("dataCacheBean")
public final class DataCacheBean {

    private static Logger logger = LoggerFactory.getLogger(DataCacheBean.class);

    private static final Integer INIT_BIT_NUMBER = 6;

    private static final Integer TEN = 10;

    private static final Integer ONE = 1;

    private static final Long MAX_KEEP_CODE = 99999L;

    private static DataCacheBean instance;

    private DataCacheBean() {

    }

    /** 已使用系统随机号的记录集合 */
    private Map<Long, Long> syscodeToIdMap = null;

    /** 可选择的系统随机号的记录集合 */
    private List<Long> syscodeBackUpList = null;

    /**
     * 获取实例方法
     * @return 实例
     */
    public static synchronized DataCacheBean getInstance() {
        if (instance == null) {
            instance = new DataCacheBean();
        }
        if (instance.syscodeToIdMap == null) {
            instance.initSyscodeToIdMap();
        }
        return instance;
    }

    /**
     * 初始化已注册号码记录集合
     * @param codeMap
     */
    public void initSyscodeToIdMap() {

        syscodeToIdMap = new HashMap<Long, Long>();

        CodeDao testBeanDao = (CodeDao) SpringContextUtils.getBeanByClass(CodeDao.class);

        List<BaseCode> codeList = testBeanDao.selectByWhr("syscode > " + MAX_KEEP_CODE);

        for (BaseCode code : codeList) {
            syscodeToIdMap.put(code.getSyscode(), code.getId());
        }

        instance.initBackUpSyscodeMap();

        codeList = null;
    }

    /**
     * 根据注册号获取注册号id
     * @param syscode 注册号
     * @return 注册号id
     */
    public Long getSyscodeId(Long syscode) {
        if (syscodeToIdMap == null) {
            syscodeToIdMap = new HashMap<Long, Long>();
        }
        if (syscodeToIdMap.containsKey(syscode)) {
            return syscodeToIdMap.get(syscode);
        } else {
            return null;
        }
    }

    /**
     * 把新的号码新的id存入缓存
     * @param syscode 注册号
     * @param id 注册号id
     */
    public synchronized void newSyscodeId(Long syscode, Long id) {
        syscodeToIdMap.put(syscode, id);
    }

    /**
     * 获取已注册的号码缓存集合
     * @return 已注册的号码缓存集合
     */
    public Map<Long, Long> getSyscodeToIdMap() {
        return syscodeToIdMap;
    }

    /**
     * 已注册的号码缓存赋值
     * @param syscodeToIdMap 新的缓存集合
     */
    public void setSyscodeToIdMap(Map<Long, Long> syscodeToIdMap) {
        instance.syscodeToIdMap = syscodeToIdMap;
    }

    /**
     * 查看注册随机号是否已经占用了
     * @param syscode 新生成的随机号
     * @return true 已存在需要重新生 false 不重复可以使用
     */
    public boolean containsSyscode(Long syscode) {
        return instance.getSyscodeToIdMap().containsKey(syscode);
    }

    /**
     * 初始化备用的系统随机号集合Map
     */
    private void initBackUpSyscodeMap() {

        Date begin = new Date();

        syscodeBackUpList = new ArrayList<Long>();

        int size = syscodeToIdMap.size();

        int bitNumber = INIT_BIT_NUMBER;

        if (String.valueOf(size).length() > INIT_BIT_NUMBER) {
            bitNumber = String.valueOf(size).length();
        }
        //是否需要去重操作
        boolean isNeedRemoveDuplicate = true;

        Long max = (long) java.lang.Math.pow(TEN, bitNumber);

        if ((long) size == max - 1) {
            isNeedRemoveDuplicate = false;
        } else {
            max = (long) java.lang.Math.pow(TEN, bitNumber - ONE);
        }

        Long maxEnd = (long) (max * TEN - ONE);

        for ( ; max < maxEnd; max++) {
            syscodeBackUpList.add(max);
        }

        if (isNeedRemoveDuplicate) {
            syscodeBackUpList.removeAll(syscodeToIdMap.keySet());
        }

        Date end = new Date();

        logger.info("Init backup syscode set time consuming : {} ms", end.getTime() - begin.getTime());
    }

    /**
     * 获取一个可用的随机编号
     * @return 系统随机号（全系统唯一）
     */
    public synchronized Long getNewSyscode() {

        Long syscode = null;

        if (VerifyEnvironmentBean.getTestFlag(DealStatus.getShade())) {

            CodeDao codeDao = (CodeDao) SpringContextUtils.getBeanByClass(CodeDao.class);

            List<Map<String, Object>> list = codeDao.query("select IFNULL(max(syscode),0) syscode from base_code where syscode < " + (99999L + 1L));

            if (list != null) {

                Map<String, Object> codeMap = list.iterator().next();

                Long maxTestCode = (Long) codeMap.get("syscode");

                if (maxTestCode.longValue() == MAX_KEEP_CODE) {
                    throw new CodeIsFullException(ErrorCode.CodeIsFull.getCode());
                } else {
                    syscode = ++maxTestCode;
                }
            } else {
                new CodeIsFullException(ErrorCode.CodeIsFull.getCode());
            }
        } else {
            Date begin = new Date();

            int index = MathUtils.randomNumberInt(1, syscodeBackUpList.size());

            syscode = syscodeBackUpList.get(index - 1);

            syscodeBackUpList.remove(syscode);

            if (syscodeBackUpList.size() == 0) {
                initBackUpSyscodeMap();
            }

            Date end = new Date();

            logger.info("Get a new syscode time consuming : {} ms", end.getTime() - begin.getTime());

        }

        return syscode;
    }

    /**
     * 查看当前还有多少备用号
     * @return 个数
     */
    public int getBackCodeCount() {
        return syscodeBackUpList.size();
    }
}
